package com.jin.pattern.prototype;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
 * 原型模式
 * 将一个对象作为原型，对其进行复制、克隆，产生一个和原对象类似的新对象
 * @author Jin
 * @datetime 2015/1/30 下午4:37:55
 */
public class Prototype implements Cloneable, Serializable {
	private static final long serialVersionUID = 2509525939745217915L;
	private int code;
	private String name;
	private Rabbit rabbit;
	public Prototype(int code, String name, Rabbit rabbit) {
		super();
		this.code = code;
		this.name = name;
		this.rabbit = rabbit;
	}
	public void setCode(int code) {
		this.code = code;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void setRabbit(Rabbit rabbit) {
		this.rabbit = rabbit;
	}
	@Override
	public String toString() {
		return "Prototype [code=" + code + ", name=" + name + ", color="
				+ rabbit.getColor() + "]";
	}
	
	/**
	 * 浅复制
	 * 基本数据类型及String类型会重新创建，但引用类型依然指向原对象
	 * @return
	 */
	public Prototype shallowClone(){
		Prototype prototype = null;
		try {
			prototype = (Prototype) super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return prototype;
	}
	
	/**
	 * 深复制
	 * 利用Object的clone方法克隆对象
	 * 对象及其引用类型的成员变量需实现Cloneable接口，并提供clone方法
	 * @return
	 * @throws CloneNotSupportedException 
	 */
	public Prototype deepClone1() throws CloneNotSupportedException{
		Prototype prototype = (Prototype) super.clone();
		prototype.setRabbit(this.rabbit.clone());
		return prototype;
	}
	
	/**
	 * 深复制
	 * 采用流的形式将对象序列化及反序列化来实现clone
	 * 对象及其引用类型的成员变量需实现Serializable接口
	 * @return
	 * @throws IOException
	 * @throws ClassNotFoundException
	 */
	public Prototype deepClone2() throws IOException, ClassNotFoundException{
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
		objectOutputStream.writeObject(this);
		
		ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
		ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
		return (Prototype) objectInputStream.readObject();
	}
	
}
